Skip to content

Zigbee2mqtt: add IEEE address and link to open Z2M#2488

Open
William-De71 wants to merge 5 commits intoGladysAssistant:masterfrom
William-De71:features/zigbee2mqtt-add-IEEE-address
Open

Zigbee2mqtt: add IEEE address and link to open Z2M#2488
William-De71 wants to merge 5 commits intoGladysAssistant:masterfrom
William-De71:features/zigbee2mqtt-add-IEEE-address

Conversation

@William-De71
Copy link
Copy Markdown
Contributor

@William-De71 William-De71 commented Mar 8, 2026

Pull Request check-list

To ensure your Pull Request can be accepted as fast as possible, make sure to review and check all of these items:

  • If your changes affect the code, did you write the tests?
  • Are tests passing? (npm test on both front/server)
  • Is the linter passing? (npm run eslint on both front/server)
  • Did you run prettier? (npm run prettier on both front/server)
  • If you are adding a new feature/service, did you run the integration comparator? (npm run compare-translations on front)
  • Did you test this pull request in real life? With real devices? If this development is a big feature or a new service, we recommend that you provide a Docker image to the community (forum) for testing before merging.
  • If your changes modify the API (REST or Node.js), did you modify the API documentation? (Documentation is based on comments in code)
  • If you are adding a new features/services which needs explanation, did you modify the user documentation? See the GitHub repo and the website.
  • Did you add fake requests data for the demo mode (front/src/config/demo.js) so that the demo website is working without a backend? (if needed) See https://demo.gladysassistant.com.

NOTE: these things are not required to open a PR and can be done afterwards / while the PR is open.

Description of change

add IEEE address and link to open Z2M on device & discover page

https://community.gladysassistant.com/t/ajout-de-lid-zigbee2mqtt-dans-la-configuration-des-appareils/9616

image

Summary by CodeRabbit

  • New Features

    • Display IEEE addresses for Zigbee2MQTT devices on device and discovery pages.
    • Add a setup field to configure the Zigbee2MQTT frontend URL.
    • Show quick links (with a small logo) to open devices in the Zigbee2MQTT web UI when available.
  • Translations

    • Added German/English/French labels and placeholders for the frontend URL and IEEE address UI.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8bdcd432-30ae-4e7b-a624-690b015519db

📥 Commits

Reviewing files that changed from the base of the PR and between 6a5094d and da09c12.

📒 Files selected for processing (1)
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
✅ Files skipped from review due to trivial changes (1)
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx

📝 Walkthrough

Walkthrough

Adds IEEE address exposure to Zigbee2MQTT devices (UI + merged discovered data), optional “Open in Zigbee2MQTT” links, a Z2M_FRONTEND_URL config (backend + setup UI), i18n entries, styles, and corresponding test/fixture updates.

Changes

Cohort / File(s) Summary
Translations
front/src/config/i18n/de.json, front/src/config/i18n/en.json, front/src/config/i18n/fr.json
Added z2mFrontendUrlLabel/z2mFrontendUrlPlaceholder, ieeeAddressLabel, openInZ2mButton; minor punctuation/anchor tweak to connectionUrl.
Device Page UI
front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx, front/src/routes/integration/all/zigbee2mqtt/device-page/style.css
Render read-only ieee_address when present and optional external link to Zigbee2MQTT device page with logo; added .z2mDeviceLink and .z2mDeviceLinkLogo styles.
Device Page Logic
front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js, front/src/routes/integration/all/zigbee2mqtt/device-page/index.js
Added getZ2mUrl action to fetch setup and compute frontend URL; merge discovered-device ieee_address into devices; inject z2mUrl and call on mount.
Discover Page UI
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx, front/src/routes/integration/all/zigbee2mqtt/discover-page/style.css
Show ieee_address and optional Zigbee2MQTT frontend link/logo in discovered device cards; added/tied styles.
Discover Page Logic
front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js, front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
Added getZ2mUrl action, call on mount, and inject z2mUrl into connected props.
Setup UI
front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js, front/src/routes/integration/all/zigbee2mqtt/setup-page/remote/SetupRemoteOptions.jsx
Mapped Z2M_FRONTEND_URL ↔ z2mFrontendUrl; added state/handler, save inclusion, and external-URL field rendering for external mode.
Backend config
server/services/zigbee2mqtt/lib/constants.js, server/services/zigbee2mqtt/lib/getConfiguration.js, server/services/zigbee2mqtt/lib/saveConfiguration.js
Introduce CONFIGURATION.Z2M_FRONTEND_URL; include in setup variables; get/save expose/persist z2mFrontendUrl.
Device conversion
server/services/zigbee2mqtt/utils/convertDevice.js
Extract ieee_address from MQTT payload and attach to Gladys device when present.
Tests & Fixtures
server/test/.../{getConfiguration,getSetup,saveConfiguration}.test.js, server/test/services/zigbee2mqtt/lib/payloads/{discovered_devices,event_device_result}.json, server/test/services/zigbee2mqtt/utils/{convertDevice.test.js,payloads/*.json}
Updated tests to expect Z2M_FRONTEND_URL retrieval/persist; added/adjusted ieee_address fields in fixtures and tests.

Sequence Diagram

sequenceDiagram
    participant User
    participant Frontend
    participant Server
    participant Variables
    participant Z2M

    User->>Frontend: Open device or discover page
    Frontend->>Frontend: componentWillMount / init
    Frontend->>Server: GET /api/v1/service/zigbee2mqtt/setup (getZ2mUrl)
    Server->>Variables: gladys.variable.getValue('Z2M_FRONTEND_URL') / other vars
    Variables-->>Server: returns z2mFrontendUrl or null
    Server-->>Frontend: respond with setup (z2mUrl)
    Frontend->>Frontend: set z2mUrl, fetch devices & discovered devices
    Frontend->>Frontend: merge discovered.ieee_address into devices
    Frontend->>User: render device entries (show ieee_address if present)
    alt ieee_address present and z2mUrl available
        User->>Frontend: Click "Open in Z2M"
        Frontend->>Z2M: Open constructed Z2M device URL in new tab
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Pierre-Gilles

Poem

🐰 I sniffed an IEEE out of the hay,
I hopped a link to Z2M without delay,
A config field tucked soft and neat,
Devices now show each little heartbeat,
Hooray — the network’s bright and gay!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main changes: adding IEEE address display and a link to open devices in Zigbee2mqtt interface, which aligns with the comprehensive changes across device/discover pages and backend configuration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js (1)

45-53: ⚠️ Potential issue | 🟠 Major

Derive z2mUrl from z2mFrontendUrl as well, and refresh it after save.

Right now z2mUrl is only computed for MQTT_MODE.LOCAL. The new remote frontend URL is loaded into configuration, but never propagated into the derived z2mUrl state, so any UI still consuming z2mUrl stays blank/stale for remote setups.

Suggested fix
 class Zigbee2mqttSetupPage extends Component {
+  getZ2mUrl = configuration => {
+    if (configuration.mqttMode === MQTT_MODE.LOCAL && this.props.session.gatewayClient === undefined) {
+      const url = new URL(config.localApiUrl);
+      return `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort || '8080'}`;
+    }
+
+    if (configuration.mqttMode === MQTT_MODE.REMOTE) {
+      return configuration.z2mFrontendUrl || null;
+    }
+
+    return null;
+  };
+
   handleZ2MStatus = zigbee2mqttStatus => {
     this.setState({ zigbee2mqttStatus });
   };
@@
       const configuration = {};
       Object.keys(VARIABLE_MAP).forEach(key => (configuration[VARIABLE_MAP[key]] = savedConfig[key]));
       this.setState({
         configuration,
+        z2mUrl: this.getZ2mUrl(configuration),
         loadZigbee2mqttConfig: RequestStatus.Success
       });
-      if (this.props.session.gatewayClient === undefined && configuration.mqttMode === MQTT_MODE.LOCAL) {
-        const url = new URL(config.localApiUrl);
-        const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort || '8080'}`;
-        this.setState({ z2mUrl });
-      }
@@
       const configuration = {};
       Object.keys(VARIABLE_MAP).forEach(key => (configuration[VARIABLE_MAP[key]] = savedConfig[key]));
       this.setState({
         configuration,
+        z2mUrl: this.getZ2mUrl(configuration),
         setupZigee2mqttStatus: RequestStatus.Success
       });

Also applies to: 68-73

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js` around
lines 45 - 53, The z2mUrl state is only set for MQTT_MODE.LOCAL and never
derived from configuration.z2mFrontendUrl, so remote setups leave z2mUrl stale;
update the logic that sets z2mUrl (the block that currently checks
this.props.session.gatewayClient and MQTT_MODE.LOCAL) to also derive z2mUrl from
configuration.z2mFrontendUrl when present, and ensure the same derivation is
applied after save/update actions (the code paths around saving the
configuration) so z2mUrl is refreshed whenever configuration is loaded or saved;
reference the state key z2mUrl, the configuration object, and MQTT_MODE.LOCAL
and z2mFrontendUrl when making the change.
🧹 Nitpick comments (1)
front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js (1)

10-25: Extract getZ2mUrl into a shared Zigbee2MQTT helper.

This block is now effectively duplicated with front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js, Lines 13-28. Any future fix to URL normalization or store clearing has to be applied twice.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js` around
lines 10 - 25, Duplicate logic in getZ2mUrl should be extracted into a shared
Zigbee2MQTT helper: create a new helper function (e.g., resolveZ2mUrl or
getZ2mUrlFromConfig) that accepts the same inputs used here (state.httpClient,
state.session, config.localApiUrl, and store.setState or return value) and
encapsulates the URL normalization and store-setting logic currently in
getZ2mUrl; export that helper and replace the inline getZ2mUrl implementations
in both front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
and device-page/actions.js to call the shared function (or await its result and
then set store state consistently), ensuring you preserve the existing behavior
for local vs external modes and the case where z2mUrl remains undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@front/src/config/i18n/de.json`:
- Around line 981-983: The translation key "connectionUrl" currently opens a
user-provided URL in a new tab using target="_blank" and must include
rel="noopener noreferrer" to prevent the opened page from accessing
window.opener; update the "connectionUrl" value (the string containing the
anchor tag) to add rel="noopener noreferrer" to the <a> element while preserving
the existing href and target attributes so the link remains functional and safe.

In `@front/src/config/i18n/en.json`:
- Line 876: The translation string "connectionUrl" contains an external anchor
with target="_blank" but lacks rel="noopener noreferrer"; update the value for
the "connectionUrl" key so the anchor tag becomes <a href="{{url}}"
target="_blank" rel="noopener noreferrer"> (i.e., add rel="noopener noreferrer"
to the anchor) to match other external links and avoid introducing an opener
relationship.

In `@front/src/config/i18n/fr.json`:
- Line 1111: The translation string "connectionUrl" currently opens an external
link with target="_blank" but omits rel attributes; update the value for the
"connectionUrl" key to include rel="noopener noreferrer" in the anchor tag so
the external page cannot access window.opener (i.e., modify the string for the
"connectionUrl" key to add rel="noopener noreferrer" to the <a> tag).

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js`:
- Around line 46-49: The action currently fails entirely if the discovered
devices call errors; wrap the second Promise
(state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })) in a try/catch or resolve it separately so that
zigbee2mqttsReceived still returns; set discoveredDevices to an empty array on
error and only attach ieeeAddress when discoveredDevices contains a match (use
the existing discoveredDevices variable and the zigbee2mqttsReceived result),
thereby preserving loaded devices even when discovery/IEEE enrichment is
unavailable.
- Around line 13-27: Clear any stale z2mUrl before attempting to load setup and
DRY the logic into a shared helper: in getZ2mUrl (and the duplicate in
discover-page/actions.js) immediately call store.setState({ z2mUrl: undefined })
or use a shared async helper (e.g., fetchZ2mUrlFromSetup) that performs
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'), returns the resolved
z2mUrl or undefined, and then call store.setState({ z2mUrl }) with that result;
replace the duplicated URL-construction branches in getZ2mUrl and the
discover-page action with a single call to the helper so both pages consistently
clear stale values and set the new z2mUrl only on success.

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx`:
- Around line 169-174: The IEEE address input in Zigbee2mqttBox.jsx is using the
disabled attribute which prevents focus and copying; change the input rendering
that references props.device.ieeeAddress to use the readOnly attribute instead
of disabled (i.e., replace disabled with readOnly on the input element) so the
value remains non-editable but selectable/focusable for support/debug flows.

In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Around line 134-152: The device URL built for opening Zigbee2MQTT is missing
the required tab segment; update the href construction that uses z2mUrl and
ieeeAddress (in the DiscoveredBox component where
href={`${z2mUrl}/#/device/0/${ieeeAddress}`} is built) to append a default tab
(e.g. `/info`) so it becomes `${z2mUrl}/#/device/0/${ieeeAddress}/info`; apply
the same fix to the analogous href in Zigbee2mqttBox.jsx to ensure both links
include the tab segment.

In `@server/services/zigbee2mqtt/utils/convertDevice.js`:
- Line 12: The server is destructuring device.ieee_address but consumers expect
device.ieeeAddress; update the destructuring to capture ieee_address as
ieeeAddress (e.g., const { friendly_name: name, definition = {}, ieee_address:
ieeeAddress } = device) and ensure the returned object from convertDevice
includes the ieeeAddress property (also fix the object construction around the
block that currently maps properties at lines referenced as 25-27) so the
emitted device has ieeeAddress available for the UI.

---

Outside diff comments:
In `@front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js`:
- Around line 45-53: The z2mUrl state is only set for MQTT_MODE.LOCAL and never
derived from configuration.z2mFrontendUrl, so remote setups leave z2mUrl stale;
update the logic that sets z2mUrl (the block that currently checks
this.props.session.gatewayClient and MQTT_MODE.LOCAL) to also derive z2mUrl from
configuration.z2mFrontendUrl when present, and ensure the same derivation is
applied after save/update actions (the code paths around saving the
configuration) so z2mUrl is refreshed whenever configuration is loaded or saved;
reference the state key z2mUrl, the configuration object, and MQTT_MODE.LOCAL
and z2mFrontendUrl when making the change.

---

Nitpick comments:
In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js`:
- Around line 10-25: Duplicate logic in getZ2mUrl should be extracted into a
shared Zigbee2MQTT helper: create a new helper function (e.g., resolveZ2mUrl or
getZ2mUrlFromConfig) that accepts the same inputs used here (state.httpClient,
state.session, config.localApiUrl, and store.setState or return value) and
encapsulates the URL normalization and store-setting logic currently in
getZ2mUrl; export that helper and replace the inline getZ2mUrl implementations
in both front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
and device-page/actions.js to call the shared function (or await its result and
then set store state consistently), ensuring you preserve the existing behavior
for local vs external modes and the case where z2mUrl remains undefined.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f96260f-13d9-4cbe-8e1e-abde79daab75

📥 Commits

Reviewing files that changed from the base of the PR and between ea7c17e and 9179d8f.

⛔ Files ignored due to path filters (1)
  • front/src/assets/integrations/logos/logo_zigbee2mqtt.png is excluded by !**/*.png
📒 Files selected for processing (25)
  • front/src/config/i18n/de.json
  • front/src/config/i18n/en.json
  • front/src/config/i18n/fr.json
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
  • front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/device-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/device-page/style.css
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/style.css
  • front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/setup-page/remote/SetupRemoteOptions.jsx
  • server/services/zigbee2mqtt/lib/constants.js
  • server/services/zigbee2mqtt/lib/getConfiguration.js
  • server/services/zigbee2mqtt/lib/saveConfiguration.js
  • server/services/zigbee2mqtt/utils/convertDevice.js
  • server/test/services/zigbee2mqtt/lib/getConfiguration.test.js
  • server/test/services/zigbee2mqtt/lib/getSetup.test.js
  • server/test/services/zigbee2mqtt/lib/payloads/discovered_devices.json
  • server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
  • server/test/services/zigbee2mqtt/lib/saveConfiguration.test.js
  • server/test/services/zigbee2mqtt/utils/convertDevice.test.js
  • server/test/services/zigbee2mqtt/utils/payloads/CCT5015.json
  • server/test/services/zigbee2mqtt/utils/payloads/ZSS-ZK-THL.json

Comment on lines +981 to +983
"connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
"z2mFrontendUrlLabel": "URL der Zigbee2mqtt-Schnittstelle",
"z2mFrontendUrlPlaceholder": "http://192.168.1.x:8080"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add rel="noopener noreferrer" to the new external link.

This string opens a user-configured URL in a new tab but still grants the opened page access to window.opener. That is avoidable here and should be closed off.

Suggested fix
-        "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
+        "connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
"z2mFrontendUrlLabel": "URL der Zigbee2mqtt-Schnittstelle",
"z2mFrontendUrlPlaceholder": "http://192.168.1.x:8080"
"connectionUrl": "URL der Zigbee2mqtt-Schnittstelle: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",
"z2mFrontendUrlLabel": "URL der Zigbee2mqtt-Schnittstelle",
"z2mFrontendUrlPlaceholder": "http://192.168.1.x:8080"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/config/i18n/de.json` around lines 981 - 983, The translation key
"connectionUrl" currently opens a user-provided URL in a new tab using
target="_blank" and must include rel="noopener noreferrer" to prevent the opened
page from accessing window.opener; update the "connectionUrl" value (the string
containing the anchor tag) to add rel="noopener noreferrer" to the <a> element
while preserving the existing href and target attributes so the link remains
functional and safe.

"mqtt": "MQTT",
"status": "Status",
"connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>"
"connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add rel="noopener noreferrer" to this external link.

This new target="_blank" link reintroduces an opener relationship. Please keep it aligned with the rest of the file’s external links.

Suggested fix
-        "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
+        "connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
"connectionUrl": "Zigbee2mqtt Interface URL: <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/config/i18n/en.json` at line 876, The translation string
"connectionUrl" contains an external anchor with target="_blank" but lacks
rel="noopener noreferrer"; update the value for the "connectionUrl" key so the
anchor tag becomes <a href="{{url}}" target="_blank" rel="noopener noreferrer">
(i.e., add rel="noopener noreferrer" to the anchor) to match other external
links and avoid introducing an opener relationship.

"mqtt": "MQTT",
"status": "Statut",
"connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>"
"connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add rel="noopener noreferrer" to the new external link.

Line 1111 opens a configured URL in a new tab with target="_blank" but no rel, so the Zigbee2MQTT frontend keeps access to window.opener.

Suggested fix
-        "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
+        "connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\">{{url}}</a>",
"connectionUrl": "URL de l'interface Zigbee2mqtt : <a href=\"{{url}}\" target=\"_blank\" rel=\"noopener noreferrer\">{{url}}</a>",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/config/i18n/fr.json` at line 1111, The translation string
"connectionUrl" currently opens an external link with target="_blank" but omits
rel attributes; update the value for the "connectionUrl" key to include
rel="noopener noreferrer" in the anchor tag so the external page cannot access
window.opener (i.e., modify the string for the "connectionUrl" key to add
rel="noopener noreferrer" to the <a> tag).

Comment on lines +13 to +27
async getZ2mUrl(state) {
try {
const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup');
if (configuration.Z2M_MQTT_MODE === 'local') {
if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) {
const url = new URL(config.localApiUrl);
const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`;
store.setState({ z2mUrl });
}
} else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) {
store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL });
}
} catch (e) {
// z2mUrl stays undefined, link won't be shown
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clear stale z2mUrl values before loading setup.

Lines 13-27 only write z2mUrl in success branches. In the SPA store, a value from a previous visit survives when setup no longer exposes a frontend URL or this request fails, so the “Open in Zigbee2mqtt” link can keep pointing to an invalid target. The same logic is duplicated in front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js, Lines 10-25, so a shared helper would keep both pages consistent.

Suggested fix
     async getZ2mUrl(state) {
+      store.setState({ z2mUrl: undefined });
       try {
         const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup');
         if (configuration.Z2M_MQTT_MODE === 'local') {
           if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) {
             const url = new URL(config.localApiUrl);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getZ2mUrl(state) {
try {
const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup');
if (configuration.Z2M_MQTT_MODE === 'local') {
if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) {
const url = new URL(config.localApiUrl);
const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`;
store.setState({ z2mUrl });
}
} else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) {
store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL });
}
} catch (e) {
// z2mUrl stays undefined, link won't be shown
}
async getZ2mUrl(state) {
store.setState({ z2mUrl: undefined });
try {
const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup');
if (configuration.Z2M_MQTT_MODE === 'local') {
if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) {
const url = new URL(config.localApiUrl);
const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`;
store.setState({ z2mUrl });
}
} else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) {
store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL });
}
} catch (e) {
// z2mUrl stays undefined, link won't be shown
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around
lines 13 - 27, Clear any stale z2mUrl before attempting to load setup and DRY
the logic into a shared helper: in getZ2mUrl (and the duplicate in
discover-page/actions.js) immediately call store.setState({ z2mUrl: undefined })
or use a shared async helper (e.g., fetchZ2mUrlFromSetup) that performs
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup'), returns the resolved
z2mUrl or undefined, and then call store.setState({ z2mUrl }) with that result;
replace the duplicated URL-construction branches in getZ2mUrl and the
discover-page action with a single call to the helper so both pages consistently
clear stale values and set the new z2mUrl only on success.

Comment on lines +46 to +49
const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t make IEEE enrichment a hard dependency for loading devices.

Lines 46-49 reject the whole action if /discovered is unavailable, even though that response is only used to attach ieeeAddress. A transient MQTT/discovery failure would now blank the saved-device list as well.

Suggested fix
-        const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
-          state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
-          state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
-        ]);
+        const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
+          state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
+          state.httpClient
+            .get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
+            .catch(() => [])
+        ]);

Based on learnings: degraded-mode return is preferred over throwing errors because preserving available data is more useful than failing fast; discovery should remain resilient.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
]);
const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
state.httpClient
.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
.catch(() => [])
]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around
lines 46 - 49, The action currently fails entirely if the discovered devices
call errors; wrap the second Promise
(state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })) in a try/catch or resolve it separately so that
zigbee2mqttsReceived still returns; set discoveredDevices to an empty array on
error and only attach ieeeAddress when discoveredDevices contains a match (use
the existing discoveredDevices variable and the zigbee2mqttsReceived result),
thereby preserving loaded devices even when discovery/IEEE enrichment is
unavailable.

Comment on lines +169 to +174
<div class="form-group">
<label class="form-label">
<Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
</label>
<input type="text" class="form-control" value={props.device.ieeeAddress} disabled />
{props.z2mUrl && (
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use readOnly instead of disabled for the IEEE address field.

A disabled input can't be focused or copied normally, which makes the new identifier harder to reuse for support/debug flows. readOnly keeps it non-editable without blocking selection.

Suggested fix
-                  <div class="form-group">
-                    <label class="form-label">
+                  <div class="form-group">
+                    <label class="form-label" for={`ieee_${props.deviceIndex}`}>
                       <Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
                     </label>
-                    <input type="text" class="form-control" value={props.device.ieeeAddress} disabled />
+                    <input
+                      id={`ieee_${props.deviceIndex}`}
+                      type="text"
+                      class="form-control"
+                      value={props.device.ieeeAddress}
+                      readOnly
+                    />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="form-group">
<label class="form-label">
<Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
</label>
<input type="text" class="form-control" value={props.device.ieeeAddress} disabled />
{props.z2mUrl && (
<div class="form-group">
<label class="form-label" for={`ieee_${props.deviceIndex}`}>
<Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
</label>
<input
id={`ieee_${props.deviceIndex}`}
type="text"
class="form-control"
value={props.device.ieeeAddress}
readOnly
/>
{props.z2mUrl && (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx`
around lines 169 - 174, The IEEE address input in Zigbee2mqttBox.jsx is using
the disabled attribute which prevents focus and copying; change the input
rendering that references props.device.ieeeAddress to use the readOnly attribute
instead of disabled (i.e., replace disabled with readOnly on the input element)
so the value remains non-editable but selectable/focusable for support/debug
flows.

Comment on lines +134 to +152
{ieeeAddress && (
<div class="form-group">
<label class="form-label">
<Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
</label>
<input type="text" class="form-control" value={ieeeAddress} disabled />
{z2mUrl && (
<a
href={`${z2mUrl}/#/device/0/${ieeeAddress}`}
target="_blank"
rel="noopener noreferrer"
class={`${style.z2mDeviceLink} mt-2 text-muted`}
>
<img src={logoZigbee2mqtt} alt="Zigbee2mqtt" class={style.z2mDeviceLinkLogo} />
<Text id="integration.zigbee2mqtt.openInZ2mButton" />
</a>
)}
</div>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Zigbee2MQTT frontend device page URL format

💡 Result:

In the current Zigbee2MQTT WindFront UI (the default frontend), device pages are hash-routed and use the device’s IEEE address plus a source index:

  • Device page (default “info” tab):
    http(s)://<host>:<port>/#/device/<sourceIdx>/<ieee_address>/info (raw.githubusercontent.com)

  • General format (any tab):
    http(s)://<host>:<port>/#/device/<sourceIdx>/<ieee_address>/<tab>
    where <tab> is one of: info | exposes | bind | reporting | settings | settings-specific | state | clusters | groups | scene | dev-console. (raw.githubusercontent.com)

If you use frontend.base_url (reverse proxy subpath), it becomes:
http(s)://<host>:<port><base_url>/#/device/<sourceIdx>/<ieee_address>/<tab>. (zigbee2mqtt.io)

Citations:


🏁 Script executed:

# Quick verification: check if there are other instances of this Z2M URL pattern in the codebase
rg 'device/0/' front/

Repository: GladysAssistant/Gladys

Length of output: 379


The Zigbee2MQTT URL is missing the required tab segment.

According to Zigbee2MQTT frontend routing, the correct format is /#/device/<sourceIdx>/<ieee_address>/<tab> where <tab> is one of: info, exposes, bind, reporting, settings, settings-specific, state, clusters, groups, scene, or dev-console.

The current URL ${z2mUrl}/#/device/0/${ieeeAddress} is incomplete. Add a default tab (typically /info):

href={`${z2mUrl}/#/device/0/${ieeeAddress}/info`}

Note: The same issue exists in front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`
around lines 134 - 152, The device URL built for opening Zigbee2MQTT is missing
the required tab segment; update the href construction that uses z2mUrl and
ieeeAddress (in the DiscoveredBox component where
href={`${z2mUrl}/#/device/0/${ieeeAddress}`} is built) to append a default tab
(e.g. `/info`) so it becomes `${z2mUrl}/#/device/0/${ieeeAddress}/info`; apply
the same fix to the analogous href in Zigbee2mqttBox.jsx to ensure both links
include the tab segment.

@William-De71 William-De71 changed the title [WIP] Zigbee2mqtt: add IEEE address and link to open Z2M Zigbee2mqtt: add IEEE address and link to open Z2M Mar 8, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (3)
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx (1)

142-142: ⚠️ Potential issue | 🟡 Minor

The Zigbee2MQTT URL is missing the required /info tab segment.

According to Z2M frontend routing, the correct format is /#/device/<sourceIdx>/<ieee_address>/<tab>. Append /info to the URL:

-                            href={`${z2mUrl}/#/device/0/${ieee_address}`}
+                            href={`${z2mUrl}/#/device/0/${ieee_address}/info`}

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`
at line 142, The generated Zigbee2MQTT device link is missing the required tab
segment; update the href template in DiscoveredBox.jsx (the expression using
z2mUrl and ieee_address) so it builds
`${z2mUrl}/#/device/0/${ieee_address}/info` (i.e., append `/info` to the
existing path) to match the Z2M frontend route format.
front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js (2)

13-27: ⚠️ Potential issue | 🟡 Minor

Clear stale z2mUrl before loading setup.

If this request fails, or setup no longer yields a usable URL, the old value remains in the store and the link can point to the wrong Zigbee2MQTT instance. Reset it before Line 15, then populate it only on success.

Suggested fix
    async getZ2mUrl(state) {
+      store.setState({ z2mUrl: undefined });
       try {
         const configuration = await state.httpClient.get('/api/v1/service/zigbee2mqtt/setup');
         if (configuration.Z2M_MQTT_MODE === 'local') {
           if (configuration.z2mTcpPort && state.session.gatewayClient === undefined) {
             const url = new URL(config.localApiUrl);
             const z2mUrl = `${url.protocol}//${url.hostname}:${configuration.z2mTcpPort}`;
             store.setState({ z2mUrl });
           }
         } else if (configuration.Z2M_MQTT_MODE === 'external' && configuration.Z2M_FRONTEND_URL) {
           store.setState({ z2mUrl: configuration.Z2M_FRONTEND_URL });
         }
       } catch (e) {
         // z2mUrl stays undefined, link won't be shown
       }
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around
lines 13 - 27, The getZ2mUrl function currently leaves a stale z2mUrl in the
store if the HTTP request fails or returns no usable URL; before calling
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup') clear the stored value
(e.g., call store.setState({ z2mUrl: undefined })) so the link is removed, then
only call store.setState to populate z2mUrl inside the existing success branches
(where configuration.Z2M_MQTT_MODE === 'local' and the external branch) and do
not set it in the catch block.

43-46: ⚠️ Potential issue | 🟠 Major

Don’t make IEEE enrichment a hard dependency for loading devices.

Line 45 makes /discovered required for the whole page load, even though it is only used to attach ieee_address. A transient discovery error now rejects the entire Promise.all and prevents the saved-device list from loading. Fall back to [] for enrichment data instead.

Suggested fix
         const [zigbee2mqttsReceived, discoveredDevices] = await Promise.all([
           state.httpClient.get('/api/v1/service/zigbee2mqtt/device', options),
-          state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
+          state.httpClient
+            .get('/api/v1/service/zigbee2mqtt/discovered', { filter_existing: false })
+            .catch(() => [])
         ]);

Based on learnings: degraded-mode return is preferred over throwing errors because preserving available data is more useful than failing fast. Discovery should remain resilient.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js` around
lines 43 - 46, The code currently treats the discovered devices fetch as a hard
dependency by using
Promise.all([state.httpClient.get('/api/v1/service/zigbee2mqtt/device',
options), state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })]) which causes the whole load to fail if the
discovered route errors; change this to allow enrichment to degrade gracefully
by either using Promise.allSettled or catching the discoveredDevices promise and
falling back to an empty array ([]) so zigbee2mqttsReceived still loads and you
can attach ieee_address only when discoveredDevices is available (reference
symbols: zigbee2mqttsReceived, discoveredDevices, Promise.all,
state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered')).
🧹 Nitpick comments (1)
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx (1)

136-139: Consider adding id/for attributes for accessibility consistency.

Other form inputs in this file (e.g., name_${deviceIndex}, room_${deviceIndex}, topic_${deviceIndex}) use id attributes with corresponding for attributes on labels. The IEEE address input lacks this pattern.

♿ Proposed fix for accessibility consistency
                       <div class="form-group">
-                        <label class="form-label">
+                        <label class="form-label" for={`ieee_address_${deviceIndex}`}>
                           <Text id="integration.zigbee2mqtt.ieeeAddressLabel" />
                         </label>
-                        <input type="text" class="form-control" value={ieee_address} disabled />
+                        <input id={`ieee_address_${deviceIndex}`} type="text" class="form-control" value={ieee_address} disabled />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`
around lines 136 - 139, The IEEE address input lacks an id/for pairing for
accessibility; update the label and input in the DiscoveredBox component to
follow the same pattern used by other fields (e.g., name_${deviceIndex},
room_${deviceIndex}). Add a unique id for the input (such as
`ieee_${deviceIndex}` or similar based on `deviceIndex`) and set the label's
htmlFor/for attribute to that id so the label is correctly associated with the
`ieee_address` input. Ensure the id value is unique per device instance and use
the same `deviceIndex` variable used elsewhere in this component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js`:
- Around line 13-27: The getZ2mUrl function currently leaves a stale z2mUrl in
the store if the HTTP request fails or returns no usable URL; before calling
state.httpClient.get('/api/v1/service/zigbee2mqtt/setup') clear the stored value
(e.g., call store.setState({ z2mUrl: undefined })) so the link is removed, then
only call store.setState to populate z2mUrl inside the existing success branches
(where configuration.Z2M_MQTT_MODE === 'local' and the external branch) and do
not set it in the catch block.
- Around line 43-46: The code currently treats the discovered devices fetch as a
hard dependency by using
Promise.all([state.httpClient.get('/api/v1/service/zigbee2mqtt/device',
options), state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered', {
filter_existing: false })]) which causes the whole load to fail if the
discovered route errors; change this to allow enrichment to degrade gracefully
by either using Promise.allSettled or catching the discoveredDevices promise and
falling back to an empty array ([]) so zigbee2mqttsReceived still loads and you
can attach ieee_address only when discoveredDevices is available (reference
symbols: zigbee2mqttsReceived, discoveredDevices, Promise.all,
state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered')).

In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Line 142: The generated Zigbee2MQTT device link is missing the required tab
segment; update the href template in DiscoveredBox.jsx (the expression using
z2mUrl and ieee_address) so it builds
`${z2mUrl}/#/device/0/${ieee_address}/info` (i.e., append `/info` to the
existing path) to match the Z2M frontend route format.

---

Nitpick comments:
In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Around line 136-139: The IEEE address input lacks an id/for pairing for
accessibility; update the label and input in the DiscoveredBox component to
follow the same pattern used by other fields (e.g., name_${deviceIndex},
room_${deviceIndex}). Add a unique id for the input (such as
`ieee_${deviceIndex}` or similar based on `deviceIndex`) and set the label's
htmlFor/for attribute to that id so the label is correctly associated with the
`ieee_address` input. Ensure the id value is unique per device instance and use
the same `deviceIndex` variable used elsewhere in this component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d564f7ee-eb42-4c1d-a402-9bcc03ff95ba

📥 Commits

Reviewing files that changed from the base of the PR and between 9179d8f and e827419.

📒 Files selected for processing (3)
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
  • front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx

@William-De71 William-De71 force-pushed the features/zigbee2mqtt-add-IEEE-address branch from e827419 to 6a5094d Compare April 4, 2026 19:52
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx (1)

142-142: ⚠️ Potential issue | 🟡 Minor

Add a default tab segment to the Zigbee2MQTT device URL.

At Line 142, the route is built as /#/device/0/${ieee_address}. This has already been flagged and still risks breaking deep-linking on Windfront versions expecting .../${tab} (commonly /info).

Suggested patch
-                            href={`${z2mUrl}/#/device/0/${ieee_address}`}
+                            href={`${z2mUrl}/#/device/0/${encodeURIComponent(ieee_address)}/info`}
In the current Zigbee2MQTT Windfront frontend, what is the expected device hash route format: /#/device/<sourceIdx>/<ieee_address> or /#/device/<sourceIdx>/<ieee_address>/<tab> (e.g., /info)?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`
at line 142, The device link built in DiscoveredBox.jsx currently uses
href={`${z2mUrl}/#/device/0/${ieee_address}`} which omits the expected tab
segment; update the href to include a default tab (e.g., `/info`) so deep-links
become `${z2mUrl}/#/device/0/${ieee_address}/info`; locate the JSX anchor using
z2mUrl and ieee_address and append the `/info` segment (or use a DEFAULT_Z2M_TAB
constant and reference that) to ensure compatibility with Windfront routes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx`:
- Line 142: The device link built in DiscoveredBox.jsx currently uses
href={`${z2mUrl}/#/device/0/${ieee_address}`} which omits the expected tab
segment; update the href to include a default tab (e.g., `/info`) so deep-links
become `${z2mUrl}/#/device/0/${ieee_address}/info`; locate the JSX anchor using
z2mUrl and ieee_address and append the `/info` segment (or use a DEFAULT_Z2M_TAB
constant and reference that) to ensure compatibility with Windfront routes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4f83f0dd-52db-4f57-8f17-c33faa253778

📥 Commits

Reviewing files that changed from the base of the PR and between e827419 and 6a5094d.

⛔ Files ignored due to path filters (1)
  • front/src/assets/integrations/logos/logo_zigbee2mqtt.png is excluded by !**/*.png
📒 Files selected for processing (25)
  • front/src/config/i18n/de.json
  • front/src/config/i18n/en.json
  • front/src/config/i18n/fr.json
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
  • front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/device-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/device-page/style.css
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoveredBox.jsx
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/style.css
  • front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/setup-page/remote/SetupRemoteOptions.jsx
  • server/services/zigbee2mqtt/lib/constants.js
  • server/services/zigbee2mqtt/lib/getConfiguration.js
  • server/services/zigbee2mqtt/lib/saveConfiguration.js
  • server/services/zigbee2mqtt/utils/convertDevice.js
  • server/test/services/zigbee2mqtt/lib/getConfiguration.test.js
  • server/test/services/zigbee2mqtt/lib/getSetup.test.js
  • server/test/services/zigbee2mqtt/lib/payloads/discovered_devices.json
  • server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
  • server/test/services/zigbee2mqtt/lib/saveConfiguration.test.js
  • server/test/services/zigbee2mqtt/utils/convertDevice.test.js
  • server/test/services/zigbee2mqtt/utils/payloads/CCT5015.json
  • server/test/services/zigbee2mqtt/utils/payloads/ZSS-ZK-THL.json
✅ Files skipped from review due to trivial changes (12)
  • server/services/zigbee2mqtt/utils/convertDevice.js
  • server/test/services/zigbee2mqtt/utils/payloads/ZSS-ZK-THL.json
  • server/services/zigbee2mqtt/lib/constants.js
  • server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
  • server/test/services/zigbee2mqtt/lib/getConfiguration.test.js
  • server/test/services/zigbee2mqtt/utils/payloads/CCT5015.json
  • front/src/routes/integration/all/zigbee2mqtt/device-page/style.css
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/style.css
  • front/src/config/i18n/en.json
  • server/test/services/zigbee2mqtt/lib/payloads/discovered_devices.json
  • front/src/config/i18n/de.json
  • server/test/services/zigbee2mqtt/utils/convertDevice.test.js
🚧 Files skipped from review as they are similar to previous changes (10)
  • server/services/zigbee2mqtt/lib/saveConfiguration.js
  • server/test/services/zigbee2mqtt/lib/getSetup.test.js
  • server/services/zigbee2mqtt/lib/getConfiguration.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/setup-page/index.js
  • front/src/routes/integration/all/zigbee2mqtt/device-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
  • front/src/routes/integration/all/zigbee2mqtt/device-page/Zigbee2mqttBox.jsx
  • front/src/config/i18n/fr.json
  • front/src/routes/integration/all/zigbee2mqtt/device-page/index.js

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.81%. Comparing base (198578d) to head (da09c12).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2488   +/-   ##
=======================================
  Coverage   98.81%   98.81%           
=======================================
  Files        1009     1009           
  Lines       17662    17665    +3     
=======================================
+ Hits        17452    17455    +3     
  Misses        210      210           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@relativeci
Copy link
Copy Markdown

relativeci bot commented Apr 4, 2026

#4119 Bundle Size — 11.6MiB (+1.41%).

da09c12(current) vs 198578d master#4106(baseline)

Warning

Bundle contains 2 duplicate packages – View duplicate packages

Bundle metrics  Change 5 changes Regression 2 regressions
                 Current
#4119
     Baseline
#4106
Regression  Initial JS 6.42MiB(+0.1%) 6.42MiB
Regression  Initial CSS 310.85KiB(+0.1%) 310.54KiB
Change  Cache Invalidation 59.36% 0%
No change  Chunks 51 51
Change  Assets 180(+0.56%) 179
Change  Modules 1644(+0.06%) 1643
No change  Duplicate Modules 21 21
No change  Duplicate Code 0.94% 0.94%
No change  Packages 136 136
No change  Duplicate Packages 2 2
Bundle size by type  Change 4 changes Regression 4 regressions
                 Current
#4119
     Baseline
#4106
Regression  JS 8.32MiB (+0.08%) 8.32MiB
Regression  IMG 2.83MiB (+5.74%) 2.68MiB
Regression  CSS 328.7KiB (+0.09%) 328.39KiB
No change  Fonts 93.55KiB 93.55KiB
Regression  Other 18.89KiB (+0.34%) 18.82KiB
No change  HTML 13.58KiB 13.58KiB

Bundle analysis reportBranch William-De71:features/zigbee2mqt...Project dashboard


Generated by RelativeCIDocumentationReport issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant